# -*- coding: utf-8 -*-
"""
__author__ = 'bingo'
__date__ = '2019/3/3'
# code is far away from bugs with the god animal protecting
    I love animals. They taste delicious.
              ┏┓      ┏┓
            ┏┛┻━━━┛┻┓
            ┃      ☃      ┃
            ┃  ┳┛  ┗┳  ┃
            ┃      ┻      ┃
            ┗━┓      ┏━┛
                ┃      ┗━━━┓
                ┃  神兽保佑    ┣┓
                ┃　永无BUG！   ┏┛
                ┗┓┓┏━┳┓┏┛
                  ┃┫┫  ┃┫┫
                  ┗┻┛  ┗┻┛
"""

from django import forms
from django.core.validators import RegexValidator
from django_redis import get_redis_connection
from user.models import User
from utils.FormMixin import FormMixin


class SmsVerificationForm(forms.Form, FormMixin):
    """
    用于注册时手机短信验证码的校验和图片验证码的校验
    """
    # telValidator为自定义的校验手机号的校验器
    telValidator = RegexValidator(r'^1[3-9]\d{9}$', message='手机号有误')
    tel = forms.CharField(max_length=11, min_length=11, validators=[telValidator, ], required=True,
                          error_messages={
                              'max_length': '手机号长度有误',
                              'min_length': '手机号长度有误',
                              'required': '手机号不能为空',
                          })
    img_code = forms.CharField(max_length=4, min_length=4, required=True,
                               error_messages={
                                   'max_length': '图片验证码有误',
                                   'min_length': '图片验证码有误',
                                   'required': '图片验证码不能为空',
                               })
    uuid = forms.UUIDField(error_messages={'required': '图片uuid不能为空'})

    def clean_tel(self):
        """
        清理特定的字段属性
        :return:
        """
        tel = self.cleaned_data.get('tel')
        if User.objects.filter(mobile=tel):
            # self.add_error('tel','手机号已被注册')
            # 两种方法都可以
            raise forms.ValidationError('手机号已被注册')
        else:
            return tel

    def clean(self):
        """
        清理和验证相互依赖的字段 clean方法 需调用父类的clean方法重构cleaned_data
        :return:
        """

        cleaned_data = super().clean()
        # 调用父类的clean方法，只有通过父类的字段校验cleaned_data才会获取到值，否则为None
        # 若 img_code未通过字段校验，则get到的为None ，对None对象操作会有异常
        # 所以需要对 img_code = cleaned_data.get('img_code', '')赋值一个默认值""，

        img_code = cleaned_data.get('img_code', '')
        uuid = cleaned_data.get('uuid')
        tel = cleaned_data.get('tel')
        # 获取数据

        image_code_key = 'img_{}'.format(uuid)
        # 通过uuid重构image_code_key

        sms_code_flag = 'sms_flag_{}'.format(tel)
        # 通过手机号重构sms_code_flag,目的在于为标记是否在60s之内

        redis_conn1 = get_redis_connection(alias='img_code')
        redis_conn2 = get_redis_connection(alias='sms_code')
        # 来连接redis数据库，根据image_code_key获取image_code

        real_image_code_origin = redis_conn1.get(image_code_key)
        # 取出的时bytes字节 if中如果直接调用会报错，对Bytes字节操作会抛出异常

        real_image_code = real_image_code_origin.decode('utf-8') if real_image_code_origin else None
        # 对以上取出的bytes解码 若没有查询到则令real_image_code=None,无法对NoneType进行操作，所以必须对他进行转化

        redis_conn1.delete(image_code_key) if (real_image_code and real_image_code == img_code.upper()) else None
        # 图片验证码缓存与用户输入的验证码校验正确后，就删除该图片验证码

        real_sms_flag = redis_conn2.get(sms_code_flag)

        if not real_image_code:
            # self.add_error('img_code','验证码不正确')
            raise forms.ValidationError('图片验证码已失效,请刷新验证码')

        if img_code.upper() != real_image_code:
            raise forms.ValidationError('图片验证码不正确')

        if real_sms_flag:
            """
            如果60s之内该标记存在，则抛出异常，即60s之内不能再次发送验证码
            """
            raise forms.ValidationError('验证码发送过于频繁')


class RetrieveVerificationForm(forms.Form, FormMixin):
    """
    用于用户忘记密码时重置密码的校验
    """
    telValidator = RegexValidator(r'^1[3-9]\d{9}$', message='非有效的手机号，请检查')
    tel = forms.CharField(max_length=11, min_length=11, validators=[telValidator, ], required=True,
                          error_messages={
                              'max_length': '非有效的手机号，请检查',
                              'min_length': '非有效的手机号，请检查',
                              'required': '手机号不能为空',
                          })

    def clean_tel(self):
        tel = self.cleaned_data.get('tel')
        redis_conn = get_redis_connection(alias='sms_code')
        sms_ret_flag = 'sms_ref_flag_{}'.format(tel)

        if not User.objects.filter(mobile=tel).exists():
            raise forms.ValidationError("该手机号尚未注册")

        if redis_conn.get(sms_ret_flag):
            """
            拒绝60s内重复发送获取验证码请求
            """
            raise forms.ValidationError('验证码发送过于频繁')
        return tel
